#include <cassert>

#include <QDebug>

#include "trianglemf.h"

TriangleMF::TriangleMF() : GraphicalMF("Triangle", 3)
{
    /* Set x values */
    for(int i = 0; i < m_size; ++i)
    {
        m_points[i].setX(i);
    }

    /* Set the y values */
    m_points[0].setY(0);
    m_points[1].setY(1);
    m_points[2].setY(0);
}

TriangleMF::TriangleMF(double newPoints[]) : GraphicalMF("Triangle", 3)
{
    /* Set the x values in accordance to the array that was passed in */
    for( int i = 0; i < m_size; ++i )
        m_points[i].setX(newPoints[i]);

    /* Set the y values */
    m_points[0].setY(0);
    m_points[1].setY(1);
    m_points[2].setY(0);
}

TriangleMF::~TriangleMF()
 {
 }

void TriangleMF::paint(QPainter *painter, const double &xShift,
                       const double &xScale, const double &yShift,
                       const double &yScale) const
{
    /* Paint in the generic GraphicalMF style */
    this->GraphicalMF::paint(painter, xShift, xScale, yShift, yScale);

    /* Draw the name of the MF above it and near the center */
    painter->drawText(xShift + xScale * (m_points[2].x() + m_points[0].x())/2,
                      yShift + yScale - 4,
                      this->getName());

    /* If this is an output MF, draw the composite */
    if( m_is_output && m_fuzzy_value <= 1 ) {

        /* If the degree of membership of this set is 0, there is nothing to
         * draw.
         */
        if( m_fuzzy_value == 0 ) return;

        /* m_fuzzy_value is what holds the probability, so we're working with
         * that.
         */
        double p = m_fuzzy_value;
        double np = 1 - p;
        double x[] = { m_points[0].x(), m_points[1].x(), m_points[2].x() };
        double y[] = { m_points[0].y(), m_points[1].y(), m_points[2].y() };

        QPointF p1(xShift + xScale * x[0], yShift + yScale * y[0]);

        QPointF p2(xShift + xScale * (x[1] * p + x[0] * np),
                   yShift + yScale * y[1] * p);

        QPointF p3(xShift + xScale * (x[2] * np + x[1] * p), p2.y());

        QPointF p4(xShift + xScale * x[2], yShift + yScale * y[2]);

        QPointF points[] = {p1, p2, p3, p4, p1};

        QBrush oldBrush = painter->brush();
        painter->setBrush(Qt::blue);
        painter->drawPolygon(points, 4);
        painter->setBrush(oldBrush);
    }
}

void TriangleMF::calculateCentroid()
{
	/*This time, I am doing the calculations in a different way.
	  *The centroid is the geometric centroid.
	  *Then the weightings of each triangle in the output function set will
	  *be calcuated as the cetroid times the probability of the answer being
	  *in that function. Rather than by calculating the area with a cutoff.
	  *Perhaps it would be fun to get this to work multiple ways and try them
	  *all to see the difference. I might be able to quickly copy my other
	  *method over here and add it as an option too. Actually, then there could
	  *be three ways to calculate the centroid. They could all be written here
	  *as functions, but the user would have to decide which one they wanted to
	  *try in the main control.
	  */
	double centroid1 = m_points[0].x() + 2.0 * (m_points[1].x() - m_points[0].x()) / 3;
	double centroid2 = m_points[1].x() + 1.0 * (m_points[2].x() - m_points[1].x()) / 3;
    m_crisp_value = (centroid1 + centroid2) / 2;

}

void TriangleMF::calculateProbability(const double& crispInput)
{
	/* same method of calculation as last time I wrote this.
	  *
	  *                  /\
	  *                 /  \
	  *                /    \
	  *               /|l2   \
	  * _____________/_|      \__________ --> x increases this way.
	  *         p[0] l1  p[1]  p[2]
	  * When the x-location ends up on a slope use similar triangles to
	  * calculate the height. The height at the top is probability value of 1.
	  * Basically the length between p[0] and p[1] divided by the height (1)
	  * is in the same ratio as the length l1/l2. Rearrange to solve for l2.
	  */
    if(crispInput <= m_points[0].x() || crispInput >= m_points[2].x())
	{
        m_fuzzy_value = 0;
	}
    else if( crispInput >= m_points[0].x() && crispInput <= m_points[1].x())
	{
		m_fuzzy_value = ((crispInput - m_points[0].x()) /
						 (m_points[1].x() - m_points[0].x()));
	}
	else /*could put an if in here, but what is the point? */
	{
		m_fuzzy_value = ((m_points[2].x() - crispInput) /
						 (m_points[2].x() - m_points[1].x()));
	}

}
